package com.lvcoding.sec3.secdemo3.validatecode.parent;

import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpSession;
import java.util.Map;

public abstract class AbstraceValidateCodeProcessor<C> implements ValidateCodeProcessor {

    /**
     * 收集系统中所有的{@link ValidateCodeGenerator}接口实现
     *
     * 这里利用了spring的依赖查找的特性：
     * 在spring容器启动时，spring看到这个map时，它会查找ValidateCodeGenerator接口的所有实现，
     * 将这些实现的bean的名称作为这个Map的key，实现作为value都存到了map中
     *
     */
    @Autowired
    private Map<String, ValidateCodeGenerator> validateCodeGenerators;

    @Override
    public void create(ServletWebRequest request) throws Exception {
        C validateCode = generate(request);
        save(request, validateCode);
        send(request, validateCode);
    }

    @Override
    @SuppressWarnings("unchecked")
    public C generate(ServletWebRequest request) {
        String type = getProcessorType(request);
        ValidateCodeGenerator validateCodeGenerator = validateCodeGenerators.get(type + "CodeGenerator");
        return (C) validateCodeGenerator.generate(request);
    }

    private String getProcessorType(ServletWebRequest request) {
        return StrUtil.subAfter(request.getRequest().getRequestURI() , "/code/", false);
    }

    /**
     * 保存验证码到session
     * @param request
     * @param code
     * @throws Exception
     */
    @Override
    public void save(ServletWebRequest request, Object code) throws Exception {
        HttpSession session = request.getRequest().getSession();
        String type = getProcessorType(request);
        session.setAttribute(SESSION_KEY_PREFIX + type.toUpperCase(), code);
    }

    /**
     * 发送校验码，由子类实现
     * @param request
     * @param validateCode
     * @throws Exception
     */
     protected abstract void send(ServletWebRequest request, C validateCode) throws Exception;
}
